import cPickle
import datetime
import random

from django.db import models
from django.test import TestCase


class MockResourceManager(models.Manager):
    def delete_old(self):
        """Delete mocks whose time-to-live has expired."""
        super(MockResourceManager, self).filter(
            alive_until__lte=datetime.datetime.now()
        ).delete()

class MockResource(models.Model):
    """An HTTP resource mocked by htmock."""
    label = models.SlugField(unique=True)
    created_on = models.DateTimeField()
    alive_until = models.DateTimeField()
    status_code = models.PositiveIntegerField()
    entity_body = models.TextField()
    
    objects = MockResourceManager()
    
    def __unicode__(self):
        return self.label
    
    class Meta:
        ordering = ['-created_on']
    
    @staticmethod
    def random_label():
        """Generate a random label (of 6 letters) for a new resource."""
        label = u''
        for i in range(6):
            label += random.choice(u'abcdefghijklmnopqrstuvwxyz')
        if MockResource.objects.filter(label=label).exists():
            return random_label()
        else:
            return label

class Header(models.Model):
    """An HTTP header sent with the response for a mock resource."""
    resource = models.ForeignKey(MockResource, related_name='headers')
    field_name = models.CharField(max_length=50)
    field_value = models.TextField()
    def __unicode__(self):
        return u'%s: %s' % (self.field_name, self.field_value)

class TracedRequest(models.Model):
    """A request for a mock resource that has been saved by htmock."""
    resource = models.ForeignKey(MockResource, related_name='requests')
    received_on = models.DateTimeField()
    remote_addr = models.CharField(max_length=50)
    method = models.CharField(max_length=10)
    _headers = models.TextField()
    _get_params = models.TextField()
    _post_params = models.TextField()
    query_string = models.TextField()
    data = models.TextField()
    
    def __unicode__(self):
        return u'%s %s' % (self.method, self.received_on)
    
    def get_headers(self):
        return cPickle.loads(self._headers.encode('ascii'))
    def set_headers(self, value):
        self._headers = cPickle.dumps(value)
    headers = property(get_headers, set_headers, "Request headers as a dict.")
    
    def get_get_params(self):
        return cPickle.loads(self._get_params.encode('ascii'))
    def set_get_params(self, value):
        self._get_params = cPickle.dumps(value)
    get_params = property(get_get_params, set_get_params,
                          "Query string parameters as a QueryDict.")
    
    def get_post_params(self):
        return cPickle.loads(self._post_params.encode('ascii'))
    def set_post_params(self, value):
        self._post_params = cPickle.dumps(value)
    post_params = property(get_post_params, set_post_params,
                           "URL-encoded body as a QueryDict.")
    
    class Meta:
        ordering = ['-received_on']


class MockResourceTests(TestCase):
    def test_delete_old(self):
        """`MockResource.objects.delete_old`"""
        now = datetime.datetime.now()
        before = now - datetime.timedelta(hours=1)
        after = now + datetime.timedelta(hours=1)
        MockResource(label=u'one', created_on=now, alive_until=after,
                     status_code=200, entity_body=u'').save()
        MockResource(label=u'two', created_on=before, alive_until=now,
                     status_code=200, entity_body=u'').save()
        self.assert_(MockResource.objects.filter(label=u'one').exists())
        self.assert_(MockResource.objects.filter(label=u'two').exists())
        MockResource.objects.delete_old()
        self.assert_(MockResource.objects.filter(label=u'one').exists())
        self.assert_(not MockResource.objects.filter(label=u'two').exists())
